Conversation
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
…9431) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
…xtended node support (#9438)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: dyc3 <1808807+dyc3@users.noreply.github.com> Co-authored-by: chansuke <501052+chansuke@users.noreply.github.com>
🦋 Changeset detectedLatest commit: 9df0386 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Merging this PR will not alter performance
Comparing Footnotes
|
WalkthroughThis pull request introduces multiple interconnected features and improvements across the Biome codebase. It adds two new nursery lint rules: Possibly related PRs
Suggested labels
✨ Finishing Touches
🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 17
🧹 Nitpick comments (7)
crates/biome_js_type_info/src/flattening/expressions.rs (1)
413-415: Consider a brief comment explaining why these variants are skipped.When all union variants are
UnknownorTypeofExpression, the function returnsNone. A short comment clarifying this is intentional (can't meaningfully call an unresolved type) would aid future readers.📝 Suggested documentation
- TypeData::Unknown | TypeData::TypeofExpression(_) => { + // Cannot resolve call on unknown or unflattened expression types; + // skip without contributing to the result union. + TypeData::Unknown | TypeData::TypeofExpression(_) => { continue; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_js_type_info/src/flattening/expressions.rs` around lines 413 - 415, Add a short explanatory comment above the match arm that skips TypeData::Unknown and TypeData::TypeofExpression in crates::biome_js_type_info::flattening::expressions.rs explaining that these variants represent unresolved types that cannot be meaningfully invoked/called, so they are intentionally ignored and when every union member is one of these the enclosing function returns None; reference the TypeData::Unknown and TypeData::TypeofExpression variants in the comment so future readers can quickly understand why the continue is used.crates/biome_js_formatter/src/js/auxiliary/template_chunk_element.rs (2)
51-58: Soft coupling betweenKNOWN_EMBED_TAGS/KNOWN_EMBED_OBJECTSandJS_DETECTORSintroduces future maintenance risk.Current sync is correct (TemplateTag entries: css, gql, graphql; TemplateExpression entries: styled, graphql). However, if
JS_DETECTORSis updated without updating these constants, embedding will silently break. Consider extracting the tag/object lists directly from detector definitions or using a build-time check to keep them in sync.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_js_formatter/src/js/auxiliary/template_chunk_element.rs` around lines 51 - 58, The constants KNOWN_EMBED_TAGS and KNOWN_EMBED_OBJECTS are duplicated subsets of the detector definitions (JS_DETECTORS -> TemplateTag/TemplateExpression) and can drift; fix by deriving these lists from JS_DETECTORS (e.g., add a function that iterates JS_DETECTORS and collects TemplateTag names into a single const/once-initialized Vec for tags and TemplateExpression names for objects) or add a compile-time/runtime assertion that compares the sets (e.g., in an init check) to fail fast if JS_DETECTORS changes; update references to use the derived collections instead of the hard-coded KNOWN_EMBED_TAGS/KNOWN_EMBED_OBJECTS, and keep the symbol names KNOWN_EMBED_TAGS and KNOWN_EMBED_OBJECTS (or replace them) so other code (TemplateChunkElement) continues to use the single source of truth.
89-98: Chained.attrs()patterns are not currently in scope.The current implementation correctly handles the patterns defined in
JS_DETECTORS:styled.div`` andstyled(Comp). Chained patterns like `styled.div.attrs({})aren't found in the codebase and aren't listed in the official detector configuration, so this isn't a gap—it's intentional scope limitation.If chained patterns become needed in future, handling
JsStaticMemberExpressioncallees (where the root object is inKNOWN_EMBED_OBJECTS) would be straightforward to add.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_js_formatter/src/js/auxiliary/template_chunk_element.rs` around lines 89 - 98, Current code in the AnyJsExpression::JsCallExpression arm only matches callee as AnyJsExpression::JsIdentifierExpression and thus misses chained patterns like styled.div.attrs``; extend the match to also accept AnyJsExpression::JsStaticMemberExpression, walk its member chain to find the root object identifier, then compare that root's name (via its name().ok()?.value_token().ok()? or equivalent) against KNOWN_EMBED_OBJECTS just like the existing identifier branch; update the logic around call.callee() handling in the JsCallExpression arm (and reuse the name lookup used for AnyJsExpression::JsIdentifierExpression) so chained static members whose root is in KNOWN_EMBED_OBJECTS are detected..github/workflows/release.yml (1)
458-463: Pass the preview version through once.Lines 461-462 mint the preview version, but the website dispatch only sends the stable release version. Forwarding the exact preview version would spare the downstream workflow from having to reverse-engineer it from
sha.Possible tidy-up
- - name: Update package.json + - name: Update package.json + id: preview-version working-directory: packages/@biomejs/wasm-web run: | + preview_version='0.0.0-rev.${{ github.sha }}' npm pkg set name='@biomejs/wasm-web' - npm pkg set version='0.0.0-rev.${{ github.sha }}' + npm pkg set version="$preview_version" + echo "preview_version=$preview_version" >> "$GITHUB_OUTPUT" @@ - name: Dispatch event to website repo uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1 with: token: ${{ secrets.BIOME_REPOSITORY_DISPATCH }} repository: ${{ env.BIOME_WEBSITE_REPO }} event-type: ${{ env.BIOME_RELEASE_CLI_EVENT }} client-payload: | - { "sha": "${{ github.sha }}", "tag": "@biomejs/biome@${{ needs.publish-cli.outputs.version }}", "version": "${{ needs.publish-cli.outputs.version }}" } + { "sha": "${{ github.sha }}", "tag": "@biomejs/biome@${{ needs.publish-cli.outputs.version }}", "version": "${{ needs.publish-cli.outputs.version }}", "previewVersion": "${{ steps.preview-version.outputs.preview_version }}" }Also applies to: 474-475
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/release.yml around lines 458 - 463, The workflow currently hardcodes the preview package version as '0.0.0-rev.${{ github.sha }}' in the "Update package.json" step but does not forward that exact string to the website dispatch; change the "Update package.json" step (add an id like set-preview-version) to compute the preview version into an output (e.g., run: preview="0.0.0-rev.${{ github.sha }}"; npm pkg set version="$preview"; echo "preview_version=$preview" >> $GITHUB_OUTPUT) and then use that output (steps.set-preview-version.outputs.preview_version) in the website dispatch payload instead of the stable version; repeat the same change for the second occurrence (the other Update package.json block) so the exact preview_version is passed through to downstream workflows.crates/biome_service/src/embed/registry.rs (2)
143-145: Minor: missing doc comment for consistency.The other resolver functions (
resolve_script_language,resolve_text_expression_language,resolve_directive_language) have doc comments, but this one doesn't. A one-liner would maintain consistency.📝 Add doc comment
+/// Resolves the guest language for a <style> tag. +/// Returns None for unsupported preprocessors (e.g., SCSS) to skip processing. fn resolve_style_language( candidate: &EmbedCandidate, _file_source: &DocumentFileSource,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_service/src/embed/registry.rs` around lines 143 - 145, Add a one-line doc comment above the resolve_style_language function to match the other resolver functions (like resolve_script_language, resolve_text_expression_language, resolve_directive_language); the comment should briefly describe that the function determines the language for style/embed candidates (e.g., "Resolve the language for style embed candidates.") so documentation style remains consistent across the resolver functions.
143-153: Consider excluding additional style preprocessors.Currently only SCSS is excluded. Other preprocessors like LESS, Sass (indented syntax), or Stylus would pass through and be parsed as CSS, which could produce confusing errors.
💡 Optional: extend exclusion to other preprocessors
fn resolve_style_language( candidate: &EmbedCandidate, _file_source: &DocumentFileSource, ) -> Option<GuestLanguage> { - // SCSS is not supported — return None to skip this element - if candidate.has_attribute_value("lang", "scss") { + // Preprocessors are not supported — return None to skip this element + if candidate.has_attribute_value("lang", "scss") + || candidate.has_attribute_value("lang", "sass") + || candidate.has_attribute_value("lang", "less") + || candidate.has_attribute_value("lang", "stylus") + { None } else { Some(GuestLanguage::Css) } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_service/src/embed/registry.rs` around lines 143 - 153, The resolver resolve_style_language currently only excludes "scss" and should also skip other style preprocessors; update resolve_style_language (and its use of EmbedCandidate::has_attribute_value) to return None when the element's lang attribute matches common preprocessors such as "less", "sass" (indented), "styl" / "stylus" (and keep "scss"), doing a case-insensitive comparison or normalizing the attribute before checking, otherwise return Some(GuestLanguage::Css); this prevents treating non-CSS preprocessors as CSS and avoids confusing parse errors.justfile (1)
59-61: Wire this intogen-all, or note that it is intentionally manual.
just readyonly runsgen-all, so this new generator is easy to forget and the checked-in Baseline data can drift. If the external-data fetch is meant to stay opt-in, a short comment here would save the next maintainer a small adventure.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@justfile` around lines 59 - 61, Add the new gen-css-baseline recipe into the gen-all flow or explicitly mark it as manual: either update the just recipe named gen-all to invoke gen-css-baseline (so just ready includes it) or add a one-line comment above the gen-css-baseline target stating that it is intentionally manual and must be run separately (so maintainers know why baseline data is not auto-generated); reference the recipe name gen-css-baseline and the existing gen-all/just ready command in your change so the intent is clear.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.changeset/add-use-baseline-css-rule.md:
- Around line 5-10: The release note example uses an invalid CSS declaration
(`accent-color: bar`) which confuses the purpose of the new rule `useBaseline`;
update the changeset text to show a syntactically valid example that
demonstrates Baseline-level incompatibility (e.g., replace the invalid
`accent-color: bar` example with a valid declaration such as `accent-color:
red`) and ensure the surrounding sentence explains that `useBaseline` will flag
valid CSS properties/values like `accent-color` when they are outside the
configured Baseline tier; keep reference to the rule name `useBaseline` and the
exact problematic snippet `accent-color: bar` so the change is easy to locate.
In @.changeset/curly-games-follow.md:
- Line 5: Edit the changeset summary line so it starts with "Fixed
[`#9432`](https://github.com/biomejs/biome/issues/9432):" and rewrite the rest to
be user-facing and grammatically correct; for example: "Fixed [`#9432`]: Imports
referenced only as JSX elements inside Astro, Vue, or Svelte templates no longer
trigger false positives from the noUnusedImports and useImportType rules."
Ensure you reference the rule names noUnusedImports and useImportType exactly as
shown and replace the current implementation-heavy sentence on that line with
this user-oriented phrasing.
In `@crates/biome_css_analyze/src/keywords.rs`:
- Around line 5756-5917: NAMED_COLORS currently mixes real CSS color keywords
with non-color generic identifiers (e.g., auto, inherit, none, revert-layer,
unset) which can incorrectly suppress non-color diagnostics; remove all
non-color tokens from NAMED_COLORS so it contains only actual color names, then
introduce a new constant (e.g., ALWAYS_SAFE_IDENTIFIERS or
NON_COLOR_SAFE_IDENTIFIERS) that holds those generic identifiers and update any
code paths that previously used NAMED_COLORS for unconditional baseline bypass
to use the new constant instead (search usages of NAMED_COLORS and replace
appropriate calls/usages with ALWAYS_SAFE_IDENTIFIERS where the intent is to
skip baseline for non-color safe identifiers).
In `@crates/biome_css_analyze/src/lint/nursery/use_baseline.rs`:
- Around line 197-214: The allowSelectors option currently only checks
CssPseudoClassIdentifier/CssPseudoElementIdentifier so functional pseudos like
:has(...) never call check_pseudo; update the visitor to also visit the
functional pseudo nodes (e.g., CssPseudoClassFunction and
CssPseudoElementFunction or the equivalent node types used in this crate) and
invoke check_pseudo for them, extracting the pseudo name from the function node
(normalize to lower-case without leading colons) the same way identifiers are
handled; apply the same change to the other similar visitor blocks referenced
(the other occurrences around the noted ranges) so allowSelectors properly
excludes functional pseudos like "has" or "highlight".
- Around line 35-37: The `@supports` exemption is implemented inconsistently: only
check_property calls is_inside_positive_supports and the ancestor walk treats
`@supports not(...) {}` as positive; fix this by computing a single boolean in
run that inspects the nearest CssSupportsAtRule ancestor's condition (find the
nearest CssSupportsAtRule node and evaluate whether its condition is a
negation/CssSupportsNotCondition) and pass/consult that boolean everywhere
(instead of calling is_inside_positive_supports or checking raw ancestor kinds
repeatedly). Update run to determine inside_positive_supports once, use that
value in check_property and in the ancestor-walk logic (and replace the raw
ancestor-kind checks in the blocks around the other affected ranges: 236-253,
382-399, 432-435) so functions, selectors, media conditions, and at-rules inside
a negated `@supports` are not exempt incorrectly.
In `@crates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.css`:
- Around line 39-45: Add a guarded :has() case inside the `@supports`
selector(:has()) block to exercise the block-scoped suppression path: modify the
`@supports` selector(:has()) rule so it contains a rule using h1:has(+ h2) (e.g.,
`@supports` selector(:has()) { h1:has(+ h2) { color: red; } }) so the fixture
tests both the guarded and unguarded :has() diagnostic paths (reference the
existing `@supports` selector(:has()) block and the h1:has(+ h2) selector).
In `@crates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.css`:
- Around line 48-52: There's a typo in the nested `@supports` block: the rule for
selector "a" uses the non-existent property "background-filter" instead of
"backdrop-filter"; update the declaration in the nested `@supports`
(backdrop-filter: auto) block so the "a" rule reads "accent-color: auto;
backdrop-filter: auto" to match the feature being tested.
- Around line 43-45: In the `@supports` block that tests accent-color and
backdrop-filter (the rule starting with "@supports (accent-color: auto) and
(backdrop-filter: auto) {") update the CSS declaration inside the "a { ... }"
selector to replace the incorrect property name "background-filter" with the
correct "backdrop-filter" (also fix the same typo where it repeats later) so the
rule uses "accent-color: auto; backdrop-filter: auto".
In `@crates/biome_css_parser/src/syntax/scss/at_rule/content_at_rule.rs`:
- Around line 34-35: The predicate is_at_scss_content_at_rule currently only
recognizes the identifier form (p.at(T![ident]) && p.cur_text() == "content"),
so update it to also accept the keyword token by returning true when
p.at(T![content]) is present; in practice modify is_at_scss_content_at_rule to
check either (p.at(T![ident]) && p.cur_text() == "content") || p.at(T![content])
so the parser recognizes both identifier and keyword tokens for the `@content`
at-rule.
In `@crates/biome_js_analyze/src/lint/nursery/no_redundant_default_export.rs`:
- Line 18: Fix the rustdoc header in no_redundant_default_export.rs: replace the
garbled sentence that reads "This rule reports new nursery lint rule `useBase
when a `default` export..." with a correct, closed code span referencing this
rule (e.g. "This rule reports the nursery lint rule
`no_redundant_default_export` when a `default` export references the same
identifier as a named export.")—ensure the backticks are balanced and the rule
name `no_redundant_default_export` is used so generated docs point to the right
rule.
In `@crates/biome_service/src/embed/registry.rs`:
- Around line 55-61: The EmbedTarget::Dynamic entry for script elements is
incorrectly providing fallback: Some(GuestLanguage::JsScript) which causes
resolve_script_language returning None for unsupported types (e.g.,
text/x-handlebars-template) to fall back to JS instead of skipping; change the
EmbedDetector::Element config to use fallback: None (or remove the fallback)
and/or update resolve_script_language to return Some(Language) for every
supported MIME/type you intend to treat (e.g., add a mapping for handlebars if
you want it parsed), and ensure callers of EmbedTarget::resolve treat a None
result as “skip this element” per the documented behavior.
In `@crates/biome_service/src/file_handlers/html.rs`:
- Around line 970-989: The content_range currently uses the quoted token_range
while content_offset and text point to the unquoted inner payload, causing
off-by-one mapping; in build_vue_directive_candidate compute an
inner_token_range (the unquoted/text-only range) from
content_token/token_range/inner_offset/inner_text and use that inner range for
EmbedContent.content_range (leaving content_offset, text, element_range
unchanged) so the directive range aligns with the unquoted payload when creating
the EmbedCandidate::Directive.
In
`@crates/biome_service/src/workspace/document/services/embedded_value_references.rs`:
- Around line 148-155: Add unit tests that exercise the JSX branch by invoking
visit_jsx_reference_identifier via parsing snippets containing <Foo /> and
<Foo.Bar /> so the references set is populated for both simple and member JSX
names; update the test module that currently covers plain JS and HTML names to
include two new cases (one for "<Foo />" and one for "<Foo.Bar />") asserting
that the collected reference tokens include "Foo" and "Foo.Bar" (or the expected
token/Text ranges) so visit_jsx_reference_identifier in the
embedded_value_references service is pinned and will fail if regressed.
In `@xtask/codegen/css.ungram`:
- Around line 2609-2614: The ScssIncludeAtRule production is missing the
optional "using (...)" clause; update ScssIncludeAtRule to accept an optional
using clause (e.g., add a ScssIncludeUsingClause or ScssUsingClause nonterminal
and include it as using: ScssIncludeUsingClause? in ScssIncludeAtRule) placed
after the include target (name) and before the arguments/block, and implement
the clause grammar to match 'using' '(' <argument list> ')' so the parser
accepts constructs like "@include theme using ($arg) { ... }".
In `@xtask/codegen/src/generate_css_baseline.rs`:
- Line 10: The constant WEB_FEATURES_DATA_URL currently points to an unversioned
URL which makes generation non-reproducible; update the const
WEB_FEATURES_DATA_URL to reference a pinned version or specific commit (e.g., by
changing the URL to include an explicit package version or commit hash) so the
generator emits stable Rust and Mode::Verify is deterministic; ensure any other
uses in this file (references near lines 532-563) are left unchanged other than
using the new pinned URL constant.
---
Nitpick comments:
In @.github/workflows/release.yml:
- Around line 458-463: The workflow currently hardcodes the preview package
version as '0.0.0-rev.${{ github.sha }}' in the "Update package.json" step but
does not forward that exact string to the website dispatch; change the "Update
package.json" step (add an id like set-preview-version) to compute the preview
version into an output (e.g., run: preview="0.0.0-rev.${{ github.sha }}"; npm
pkg set version="$preview"; echo "preview_version=$preview" >> $GITHUB_OUTPUT)
and then use that output (steps.set-preview-version.outputs.preview_version) in
the website dispatch payload instead of the stable version; repeat the same
change for the second occurrence (the other Update package.json block) so the
exact preview_version is passed through to downstream workflows.
In `@crates/biome_js_formatter/src/js/auxiliary/template_chunk_element.rs`:
- Around line 51-58: The constants KNOWN_EMBED_TAGS and KNOWN_EMBED_OBJECTS are
duplicated subsets of the detector definitions (JS_DETECTORS ->
TemplateTag/TemplateExpression) and can drift; fix by deriving these lists from
JS_DETECTORS (e.g., add a function that iterates JS_DETECTORS and collects
TemplateTag names into a single const/once-initialized Vec for tags and
TemplateExpression names for objects) or add a compile-time/runtime assertion
that compares the sets (e.g., in an init check) to fail fast if JS_DETECTORS
changes; update references to use the derived collections instead of the
hard-coded KNOWN_EMBED_TAGS/KNOWN_EMBED_OBJECTS, and keep the symbol names
KNOWN_EMBED_TAGS and KNOWN_EMBED_OBJECTS (or replace them) so other code
(TemplateChunkElement) continues to use the single source of truth.
- Around line 89-98: Current code in the AnyJsExpression::JsCallExpression arm
only matches callee as AnyJsExpression::JsIdentifierExpression and thus misses
chained patterns like styled.div.attrs``; extend the match to also accept
AnyJsExpression::JsStaticMemberExpression, walk its member chain to find the
root object identifier, then compare that root's name (via its
name().ok()?.value_token().ok()? or equivalent) against KNOWN_EMBED_OBJECTS just
like the existing identifier branch; update the logic around call.callee()
handling in the JsCallExpression arm (and reuse the name lookup used for
AnyJsExpression::JsIdentifierExpression) so chained static members whose root is
in KNOWN_EMBED_OBJECTS are detected.
In `@crates/biome_js_type_info/src/flattening/expressions.rs`:
- Around line 413-415: Add a short explanatory comment above the match arm that
skips TypeData::Unknown and TypeData::TypeofExpression in
crates::biome_js_type_info::flattening::expressions.rs explaining that these
variants represent unresolved types that cannot be meaningfully invoked/called,
so they are intentionally ignored and when every union member is one of these
the enclosing function returns None; reference the TypeData::Unknown and
TypeData::TypeofExpression variants in the comment so future readers can quickly
understand why the continue is used.
In `@crates/biome_service/src/embed/registry.rs`:
- Around line 143-145: Add a one-line doc comment above the
resolve_style_language function to match the other resolver functions (like
resolve_script_language, resolve_text_expression_language,
resolve_directive_language); the comment should briefly describe that the
function determines the language for style/embed candidates (e.g., "Resolve the
language for style embed candidates.") so documentation style remains consistent
across the resolver functions.
- Around line 143-153: The resolver resolve_style_language currently only
excludes "scss" and should also skip other style preprocessors; update
resolve_style_language (and its use of EmbedCandidate::has_attribute_value) to
return None when the element's lang attribute matches common preprocessors such
as "less", "sass" (indented), "styl" / "stylus" (and keep "scss"), doing a
case-insensitive comparison or normalizing the attribute before checking,
otherwise return Some(GuestLanguage::Css); this prevents treating non-CSS
preprocessors as CSS and avoids confusing parse errors.
In `@justfile`:
- Around line 59-61: Add the new gen-css-baseline recipe into the gen-all flow
or explicitly mark it as manual: either update the just recipe named gen-all to
invoke gen-css-baseline (so just ready includes it) or add a one-line comment
above the gen-css-baseline target stating that it is intentionally manual and
must be run separately (so maintainers know why baseline data is not
auto-generated); reference the recipe name gen-css-baseline and the existing
gen-all/just ready command in your change so the intent is clear.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 8429aaee-fc70-40b3-b3b2-75557e2bb1ed
⛔ Files ignored due to path filters (67)
Cargo.lockis excluded by!**/*.lockand included by**crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rsis excluded by!**/migrate/eslint_any_rule_to_biome.rsand included by**crates/biome_cli/tests/snapshots/main_cases_handle_astro_files/use_import_type_not_triggered_for_components_in_template.snapis excluded by!**/*.snapand included by**crates/biome_cli/tests/snapshots/main_cases_rules_via_dependencies/enables_rules_via_dependencies_when_setting_domains_in_config.snapis excluded by!**/*.snapand included by**crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.allow-lists.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.newly.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.year-2021.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.year-2022.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.allow-lists.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.newly.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.year.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/suspicious/noUselessEscapeInString/invalid.css.snapis excluded by!**/*.snapand included by**crates/biome_css_analyze/tests/specs/suspicious/noUselessEscapeInString/valid.css.snapis excluded by!**/*.snapand included by**crates/biome_css_factory/src/generated/node_factory.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_factory/src/generated/syntax_factory.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_formatter/tests/specs/css/scss/at-rule/content.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/css/scss/at-rule/for.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/css/scss/at-rule/function.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/css/scss/at-rule/include.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/css/scss/at-rule/mixin.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/css/scss/at-rule/return.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_function_error.css.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/content.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/for.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/function.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/include.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/mixin.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/return.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/tailwind/when-disabled/utility-with-slash.css.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/content.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/for.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/function.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/include.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/mixin.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/return.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/tailwind/utility/with-slash.css.snapis excluded by!**/*.snapand included by**crates/biome_css_syntax/src/generated/kind.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_syntax/src/generated/macros.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_syntax/src/generated/nodes.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_syntax/src/generated/nodes_mut.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_js_analyze/tests/specs/a11y/useSemanticElements/invalid.jsx.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/a11y/useSemanticElements/invalid_self_closing.jsx.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/a11y/useSemanticElements/valid.jsx.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/complexity/useOptionalChain/validLogicalAndUnrelatedOperands.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noFloatingPromises/issue6606.ts.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noFloatingPromises/issue6606_invalid.ts.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noMisusedPromises/recordInvalid.ts.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noMisusedPromises/recordValid.ts.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useArraySortCompare/recordInvalid.ts.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useArraySortCompare/recordValid.ts.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useAwaitThenable/recordInvalid.ts.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useAwaitThenable/recordValid.ts.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useImportsFirst/invalid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useImportsFirst/invalid_all_after.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useImportsFirst/invalid_mixed.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useImportsFirst/valid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useImportsFirst/valid_directive.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/useImportsFirst/valid_with_export.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/security/noBlankTarget/invalid.jsx.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/security/noBlankTarget/valid.jsx.snapis excluded by!**/*.snapand included by**crates/biome_service/src/workspace/snapshots/biome_service__workspace__server__tests__issue_9131.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (143)
.changeset/add-use-baseline-css-rule.md.changeset/add-use-imports-first.md.changeset/curly-games-follow.md.changeset/fix-css-unicode-escape-in-string.md.changeset/fix-embedded-template-crash.md.changeset/fix-tailwind-utility-slash.md.changeset/fix-use-semantic-elements-base-concepts.md.changeset/lovely-clouds-change.md.changeset/resolve-record-type.md.github/workflows/release.ymlcrates/biome_analyze/src/rule.rscrates/biome_cli/tests/cases/handle_astro_files.rscrates/biome_css_analyze/Cargo.tomlcrates/biome_css_analyze/src/baseline_data.rscrates/biome_css_analyze/src/keywords.rscrates/biome_css_analyze/src/lib.rscrates/biome_css_analyze/src/lint/nursery/use_baseline.rscrates/biome_css_analyze/src/lint/suspicious/no_useless_escape_in_string.rscrates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.allow-lists.csscrates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.allow-lists.options.jsoncrates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.csscrates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.newly.csscrates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.newly.options.jsoncrates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.year-2021.csscrates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.year-2021.options.jsoncrates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.year-2022.csscrates/biome_css_analyze/tests/specs/nursery/useBaseline/invalid.year-2022.options.jsoncrates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.allow-lists.csscrates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.allow-lists.options.jsoncrates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.csscrates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.newly.csscrates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.newly.options.jsoncrates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.year.csscrates/biome_css_analyze/tests/specs/nursery/useBaseline/valid.year.options.jsoncrates/biome_css_analyze/tests/specs/suspicious/noUselessEscapeInString/invalid.csscrates/biome_css_analyze/tests/specs/suspicious/noUselessEscapeInString/valid.csscrates/biome_css_formatter/src/css/any/at_rule.rscrates/biome_css_formatter/src/generated.rscrates/biome_css_formatter/src/scss/any/include_target.rscrates/biome_css_formatter/src/scss/any/mod.rscrates/biome_css_formatter/src/scss/any/parameter.rscrates/biome_css_formatter/src/scss/auxiliary/include_argument_list.rscrates/biome_css_formatter/src/scss/auxiliary/mod.rscrates/biome_css_formatter/src/scss/auxiliary/parameter.rscrates/biome_css_formatter/src/scss/auxiliary/parameter_default_value.rscrates/biome_css_formatter/src/scss/auxiliary/parameter_list.rscrates/biome_css_formatter/src/scss/lists/mod.rscrates/biome_css_formatter/src/scss/lists/parameter_item_list.rscrates/biome_css_formatter/src/scss/statements/content_at_rule.rscrates/biome_css_formatter/src/scss/statements/for_at_rule.rscrates/biome_css_formatter/src/scss/statements/function_at_rule.rscrates/biome_css_formatter/src/scss/statements/include_at_rule.rscrates/biome_css_formatter/src/scss/statements/mixin_at_rule.rscrates/biome_css_formatter/src/scss/statements/mod.rscrates/biome_css_formatter/src/scss/statements/return_at_rule.rscrates/biome_css_formatter/tests/specs/css/scss/at-rule/content.scsscrates/biome_css_formatter/tests/specs/css/scss/at-rule/for.scsscrates/biome_css_formatter/tests/specs/css/scss/at-rule/function.scsscrates/biome_css_formatter/tests/specs/css/scss/at-rule/include.scsscrates/biome_css_formatter/tests/specs/css/scss/at-rule/mixin.scsscrates/biome_css_formatter/tests/specs/css/scss/at-rule/return.scsscrates/biome_css_parser/src/lexer/mod.rscrates/biome_css_parser/src/lexer/tests.rscrates/biome_css_parser/src/syntax/at_rule/mod.rscrates/biome_css_parser/src/syntax/at_rule/tailwind.rscrates/biome_css_parser/src/syntax/scss/at_rule/content_at_rule.rscrates/biome_css_parser/src/syntax/scss/at_rule/for_at_rule.rscrates/biome_css_parser/src/syntax/scss/at_rule/function_at_rule.rscrates/biome_css_parser/src/syntax/scss/at_rule/if_at_rule.rscrates/biome_css_parser/src/syntax/scss/at_rule/include_at_rule.rscrates/biome_css_parser/src/syntax/scss/at_rule/mixin_at_rule.rscrates/biome_css_parser/src/syntax/scss/at_rule/mod.rscrates/biome_css_parser/src/syntax/scss/at_rule/parameter.rscrates/biome_css_parser/src/syntax/scss/at_rule/return_at_rule.rscrates/biome_css_parser/src/syntax/scss/mod.rscrates/biome_css_parser/src/syntax/value/function/mod.rscrates/biome_css_parser/src/syntax/value/function/parameter.rscrates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/content.scsscrates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/for.scsscrates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/function.scsscrates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/include.scsscrates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/mixin.scsscrates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/return.scsscrates/biome_css_parser/tests/css_test_suite/error/tailwind/when-disabled/utility-with-slash.csscrates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/content.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/for.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/function.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/include.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/mixin.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/return.scsscrates/biome_css_parser/tests/css_test_suite/ok/tailwind/utility/with-slash.csscrates/biome_grit_patterns/src/grit_target_language/css_target_language/constants.rscrates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rscrates/biome_js_analyze/src/lint/a11y/use_semantic_elements.rscrates/biome_js_analyze/src/lint/complexity/use_optional_chain.rscrates/biome_js_analyze/src/lint/nursery/no_redundant_default_export.rscrates/biome_js_analyze/src/lint/nursery/use_await_thenable.rscrates/biome_js_analyze/src/lint/nursery/use_imports_first.rscrates/biome_js_analyze/src/lint/security/no_blank_target.rscrates/biome_js_analyze/tests/specs/a11y/useSemanticElements/invalid.jsxcrates/biome_js_analyze/tests/specs/a11y/useSemanticElements/invalid_self_closing.jsxcrates/biome_js_analyze/tests/specs/a11y/useSemanticElements/valid.jsxcrates/biome_js_analyze/tests/specs/complexity/useOptionalChain/validLogicalAndUnrelatedOperands.jscrates/biome_js_analyze/tests/specs/nursery/noFloatingPromises/issue6606.tscrates/biome_js_analyze/tests/specs/nursery/noFloatingPromises/issue6606_invalid.tscrates/biome_js_analyze/tests/specs/nursery/noMisusedPromises/recordInvalid.tscrates/biome_js_analyze/tests/specs/nursery/noMisusedPromises/recordValid.tscrates/biome_js_analyze/tests/specs/nursery/useArraySortCompare/recordInvalid.tscrates/biome_js_analyze/tests/specs/nursery/useArraySortCompare/recordValid.tscrates/biome_js_analyze/tests/specs/nursery/useAwaitThenable/recordInvalid.tscrates/biome_js_analyze/tests/specs/nursery/useAwaitThenable/recordValid.tscrates/biome_js_analyze/tests/specs/nursery/useImportsFirst/invalid.jscrates/biome_js_analyze/tests/specs/nursery/useImportsFirst/invalid_all_after.jscrates/biome_js_analyze/tests/specs/nursery/useImportsFirst/invalid_mixed.jscrates/biome_js_analyze/tests/specs/nursery/useImportsFirst/valid.jscrates/biome_js_analyze/tests/specs/nursery/useImportsFirst/valid_directive.jscrates/biome_js_analyze/tests/specs/nursery/useImportsFirst/valid_with_export.jscrates/biome_js_analyze/tests/specs/security/noBlankTarget/invalid.jsxcrates/biome_js_analyze/tests/specs/security/noBlankTarget/valid.jsxcrates/biome_js_formatter/src/js/auxiliary/template_chunk_element.rscrates/biome_js_type_info/src/flattening/expressions.rscrates/biome_js_type_info/src/resolver.rscrates/biome_js_type_info/src/type_data.rscrates/biome_rowan/src/ast/mod.rscrates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/use_baseline.rscrates/biome_rule_options/src/use_imports_first.rscrates/biome_service/src/embed/detector.rscrates/biome_service/src/embed/mod.rscrates/biome_service/src/embed/registry.rscrates/biome_service/src/embed/types.rscrates/biome_service/src/file_handlers/html.rscrates/biome_service/src/file_handlers/javascript.rscrates/biome_service/src/lib.rscrates/biome_service/src/workspace/document/services/embedded_value_references.rscrates/biome_service/src/workspace/server.tests.rsjustfilextask/codegen/Cargo.tomlxtask/codegen/css.ungramxtask/codegen/src/css_kinds_src.rsxtask/codegen/src/generate_css_baseline.rsxtask/codegen/src/lib.rsxtask/codegen/src/main.rs
💤 Files with no reviewable changes (2)
- crates/biome_js_analyze/tests/specs/a11y/useSemanticElements/invalid.jsx
- crates/biome_js_analyze/tests/specs/a11y/useSemanticElements/invalid_self_closing.jsx
| Added new nursery lint rule `useBaseline` for CSS. The rule reports when CSS properties, property values, at-rules, media conditions, functions, or pseudo-selectors are not part of the configured [Baseline](https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility) tier. | ||
|
|
||
| For example, *at the time of writing*, the rule will trigger for the use of `accent-color` because it has limited availability: | ||
|
|
||
| ```css | ||
| a { accent-color: bar; } |
There was a problem hiding this comment.
Use a valid CSS example in the release note.
accent-color: bar is invalid CSS regardless of Baseline support, so it muddies what useBaseline is actually adding. A valid declaration such as accent-color: red would demonstrate the new rule cleanly.
Based on learnings: “For rule changes in changesets, clearly demonstrate what is now invalid that wasn't before.”
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.changeset/add-use-baseline-css-rule.md around lines 5 - 10, The release
note example uses an invalid CSS declaration (`accent-color: bar`) which
confuses the purpose of the new rule `useBaseline`; update the changeset text to
show a syntactically valid example that demonstrates Baseline-level
incompatibility (e.g., replace the invalid `accent-color: bar` example with a
valid declaration such as `accent-color: red`) and ensure the surrounding
sentence explains that `useBaseline` will flag valid CSS properties/values like
`accent-color` when they are outside the configured Baseline tier; keep
reference to the rule name `useBaseline` and the exact problematic snippet
`accent-color: bar` so the change is easy to locate.
| "@biomejs/biome": patch | ||
| --- | ||
|
|
||
| Fixed [#9432](https://github.com/biomejs/biome/issues/9432): Values referenced as a JSX element in Astro/Vue/Svelte templates are now correctly detected; `noUnusedImports` and `useImportType` rules no longer reports these values as false positives. |
There was a problem hiding this comment.
Make the changeset a bit more user-facing.
Line 5 reads a touch implementation-heavy, and “rules no longer reports” should be “rules no longer report”. I’d rephrase it around the user impact, e.g. imports used only in Astro/Vue/Svelte template JSX no longer trigger false positives from noUnusedImports and useImportType. As per coding guidelines, changeset descriptions must be written for end users and bug fix changesets should start with Fixed [#NUMBER](issue link): ....
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.changeset/curly-games-follow.md at line 5, Edit the changeset summary line
so it starts with "Fixed [`#9432`](https://github.com/biomejs/biome/issues/9432):"
and rewrite the rest to be user-facing and grammatically correct; for example:
"Fixed [`#9432`]: Imports referenced only as JSX elements inside Astro, Vue, or
Svelte templates no longer trigger false positives from the noUnusedImports and
useImportType rules." Ensure you reference the rule names noUnusedImports and
useImportType exactly as shown and replace the current implementation-heavy
sentence on that line with this user-oriented phrasing.
| // CSS named colors are CssIdentifier tokens in property values. | ||
| // We exclude them from property-value baseline checks because they're | ||
| // universally supported regardless of baseline data. | ||
| pub(crate) const NAMED_COLORS: &[&str] = &[ | ||
| "aliceblue", | ||
| "antiquewhite", | ||
| "aqua", | ||
| "aquamarine", | ||
| "auto", | ||
| "azure", | ||
| "beige", | ||
| "bisque", | ||
| "black", | ||
| "blanchedalmond", | ||
| "blue", | ||
| "blueviolet", | ||
| "brown", | ||
| "burlywood", | ||
| "cadetblue", | ||
| "chartreuse", | ||
| "chocolate", | ||
| "coral", | ||
| "cornflowerblue", | ||
| "cornsilk", | ||
| "crimson", | ||
| "currentcolor", | ||
| "cyan", | ||
| "darkblue", | ||
| "darkcyan", | ||
| "darkgoldenrod", | ||
| "darkgray", | ||
| "darkgreen", | ||
| "darkgrey", | ||
| "darkkhaki", | ||
| "darkmagenta", | ||
| "darkolivegreen", | ||
| "darkorange", | ||
| "darkorchid", | ||
| "darkred", | ||
| "darksalmon", | ||
| "darkseagreen", | ||
| "darkslateblue", | ||
| "darkslategray", | ||
| "darkslategrey", | ||
| "darkturquoise", | ||
| "darkviolet", | ||
| "deeppink", | ||
| "deepskyblue", | ||
| "dimgray", | ||
| "dimgrey", | ||
| "dodgerblue", | ||
| "firebrick", | ||
| "floralwhite", | ||
| "forestgreen", | ||
| "fuchsia", | ||
| "gainsboro", | ||
| "ghostwhite", | ||
| "gold", | ||
| "goldenrod", | ||
| "gray", | ||
| "green", | ||
| "greenyellow", | ||
| "grey", | ||
| "honeydew", | ||
| "hotpink", | ||
| "indianred", | ||
| "indigo", | ||
| "inherit", | ||
| "initial", | ||
| "ivory", | ||
| "khaki", | ||
| "lavender", | ||
| "lavenderblush", | ||
| "lawngreen", | ||
| "lemonchiffon", | ||
| "lightblue", | ||
| "lightcoral", | ||
| "lightcyan", | ||
| "lightgoldenrodyellow", | ||
| "lightgray", | ||
| "lightgreen", | ||
| "lightgrey", | ||
| "lightpink", | ||
| "lightsalmon", | ||
| "lightseagreen", | ||
| "lightskyblue", | ||
| "lightslategray", | ||
| "lightslategrey", | ||
| "lightsteelblue", | ||
| "lightyellow", | ||
| "lime", | ||
| "limegreen", | ||
| "linen", | ||
| "magenta", | ||
| "maroon", | ||
| "mediumaquamarine", | ||
| "mediumblue", | ||
| "mediumorchid", | ||
| "mediumpurple", | ||
| "mediumseagreen", | ||
| "mediumslateblue", | ||
| "mediumspringgreen", | ||
| "mediumturquoise", | ||
| "mediumvioletred", | ||
| "midnightblue", | ||
| "mintcream", | ||
| "mistyrose", | ||
| "moccasin", | ||
| "navajowhite", | ||
| "navy", | ||
| "none", | ||
| "oldlace", | ||
| "olive", | ||
| "olivedrab", | ||
| "orange", | ||
| "orangered", | ||
| "orchid", | ||
| "palegoldenrod", | ||
| "palegreen", | ||
| "paleturquoise", | ||
| "palevioletred", | ||
| "papayawhip", | ||
| "peachpuff", | ||
| "peru", | ||
| "pink", | ||
| "plum", | ||
| "powderblue", | ||
| "purple", | ||
| "rebeccapurple", | ||
| "red", | ||
| "revert", | ||
| "revert-layer", | ||
| "rosybrown", | ||
| "royalblue", | ||
| "saddlebrown", | ||
| "salmon", | ||
| "sandybrown", | ||
| "seagreen", | ||
| "seashell", | ||
| "sienna", | ||
| "silver", | ||
| "skyblue", | ||
| "slateblue", | ||
| "slategray", | ||
| "slategrey", | ||
| "snow", | ||
| "springgreen", | ||
| "steelblue", | ||
| "tan", | ||
| "teal", | ||
| "thistle", | ||
| "tomato", | ||
| "transparent", | ||
| "turquoise", | ||
| "unset", | ||
| "violet", | ||
| "wheat", | ||
| "white", | ||
| "whitesmoke", | ||
| "yellow", | ||
| "yellowgreen", | ||
| ]; |
There was a problem hiding this comment.
Keep NAMED_COLORS colour-only.
This list now includes generic keywords like auto, inherit, initial, none, revert, revert-layer, and unset. If NAMED_COLORS is used as an unconditional baseline bypass, those entries will hide real diagnostics for non-colour values — revert-layer is the sharpest edge here. Please split the “always-safe identifiers” from actual colour names, or keep only colour keywords in this constant.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/biome_css_analyze/src/keywords.rs` around lines 5756 - 5917,
NAMED_COLORS currently mixes real CSS color keywords with non-color generic
identifiers (e.g., auto, inherit, none, revert-layer, unset) which can
incorrectly suppress non-color diagnostics; remove all non-color tokens from
NAMED_COLORS so it contains only actual color names, then introduce a new
constant (e.g., ALWAYS_SAFE_IDENTIFIERS or NON_COLOR_SAFE_IDENTIFIERS) that
holds those generic identifiers and update any code paths that previously used
NAMED_COLORS for unconditional baseline bypass to use the new constant instead
(search usages of NAMED_COLORS and replace appropriate calls/usages with
ALWAYS_SAFE_IDENTIFIERS where the intent is to skip baseline for non-color safe
identifiers).
| /// Code inside `@supports` blocks is exempt: if you feature-detect a capability before | ||
| /// using it, the rule does not flag it. | ||
| /// |
There was a problem hiding this comment.
The @supports exemption will misfire.
Only check_property consults is_inside_positive_supports, so functions, selectors, media conditions, and at-rules inside @supports blocks still report. The ancestor walk also treats @supports not (...) { ... } as positive for block contents, because CssSupportsNotCondition is not an ancestor of the body. Gate this once in run by inspecting the nearest CssSupportsAtRule condition instead of raw ancestor kinds.
Also applies to: 236-253, 382-399, 432-435
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/biome_css_analyze/src/lint/nursery/use_baseline.rs` around lines 35 -
37, The `@supports` exemption is implemented inconsistently: only check_property
calls is_inside_positive_supports and the ancestor walk treats `@supports
not(...) {}` as positive; fix this by computing a single boolean in run that
inspects the nearest CssSupportsAtRule ancestor's condition (find the nearest
CssSupportsAtRule node and evaluate whether its condition is a
negation/CssSupportsNotCondition) and pass/consult that boolean everywhere
(instead of calling is_inside_positive_supports or checking raw ancestor kinds
repeatedly). Update run to determine inside_positive_supports once, use that
value in check_property and in the ancestor-walk logic (and replace the raw
ancestor-kind checks in the blocks around the other affected ranges: 236-253,
382-399, 432-435) so functions, selectors, media conditions, and at-rules inside
a negated `@supports` are not exempt incorrectly.
| /// ### `allowSelectors` | ||
| /// | ||
| /// A list of CSS pseudo-class or pseudo-element names to exclude from checking | ||
| /// (without `:` or `::`, case-insensitive). | ||
| /// | ||
| /// Default: `[]` | ||
| /// | ||
| /// ```json,options | ||
| /// { | ||
| /// "options": { | ||
| /// "allowSelectors": ["has"] | ||
| /// } | ||
| /// } | ||
| /// ``` | ||
| /// | ||
| /// ```css,use_options | ||
| /// h1:has(+ h2) { margin: 0; } | ||
| /// ``` |
There was a problem hiding this comment.
allowSelectors cannot affect functional pseudos yet.
The query only visits CssPseudoClassIdentifier and CssPseudoElementIdentifier, so selectors such as :has(...) or ::highlight(...) never reach check_pseudo. The allowSelectors: ["has"] example above will therefore still behave as if nothing was allowed.
Also applies to: 238-249, 280-288
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/biome_css_analyze/src/lint/nursery/use_baseline.rs` around lines 197 -
214, The allowSelectors option currently only checks
CssPseudoClassIdentifier/CssPseudoElementIdentifier so functional pseudos like
:has(...) never call check_pseudo; update the visitor to also visit the
functional pseudo nodes (e.g., CssPseudoClassFunction and
CssPseudoElementFunction or the equivalent node types used in this crate) and
invoke check_pseudo for them, extracting the pseudo name from the function node
(normalize to lower-case without leading colons) the same way identifiers are
handled; apply the same change to the other similar visitor blocks referenced
(the other occurrences around the noted ranges) so allowSelectors properly
excludes functional pseudos like "has" or "highlight".
| fn build_vue_directive_candidate( | ||
| initializer: &HtmlAttributeInitializerClause, | ||
| is_event_handler: bool, | ||
| ) -> Option<EmbedCandidate> { | ||
| let value_node = initializer.value().ok()?; | ||
| let html_string = value_node.as_html_string()?; | ||
| let content_token = html_string.value_token().ok()?; | ||
| let inner_text = html_string.inner_string_text().ok()?; | ||
| let token_range = content_token.text_trimmed_range(); | ||
| let inner_offset = token_range.start() + TextSize::from(1); | ||
|
|
||
| let document_file_source = DocumentFileSource::Js(file_source); | ||
| Some(EmbedCandidate::Directive { | ||
| content: EmbedContent { | ||
| element_range: initializer.range(), | ||
| content_range: token_range, | ||
| content_offset: inner_offset, | ||
| text: inner_text, | ||
| }, | ||
| is_event_handler, | ||
| }) |
There was a problem hiding this comment.
Keep the directive range aligned with the unquoted payload.
Here text and content_offset point at the inner expression, but content_range still spans the surrounding quotes. That cheeky off-by-one pair will push embedded edits and mapped diagnostics onto the quotes for Vue directives like @click="handler()".
🩹 Suggested fix
let content_token = html_string.value_token().ok()?;
let inner_text = html_string.inner_string_text().ok()?;
let token_range = content_token.text_trimmed_range();
let inner_offset = token_range.start() + TextSize::from(1);
+ let inner_range = biome_rowan::TextRange::new(
+ inner_offset,
+ token_range.end() - TextSize::from(1),
+ );
Some(EmbedCandidate::Directive {
content: EmbedContent {
element_range: initializer.range(),
- content_range: token_range,
- content_offset: inner_offset,
+ content_range: inner_range,
+ content_offset: inner_range.start(),
text: inner_text,
},
is_event_handler,
})🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/biome_service/src/file_handlers/html.rs` around lines 970 - 989, The
content_range currently uses the quoted token_range while content_offset and
text point to the unquoted inner payload, causing off-by-one mapping; in
build_vue_directive_candidate compute an inner_token_range (the
unquoted/text-only range) from content_token/token_range/inner_offset/inner_text
and use that inner range for EmbedContent.content_range (leaving content_offset,
text, element_range unchanged) so the directive range aligns with the unquoted
payload when creating the EmbedCandidate::Directive.
| GuestLanguage::Css => { | ||
| let css_source = if ctx.host_file_source.is_html() { | ||
| CssFileSource::css() | ||
| .with_embedding_kind(CssEmbeddingKind::Html(EmbeddingHtmlKind::Html)) | ||
| } else if ctx.host_file_source.is_vue() { | ||
| // Vue: <style scoped> and <style module> are component-local. | ||
| // Plain <style> (no attribute) leaks into the global scope. | ||
| let applicability = | ||
| if candidate.has_attribute("scoped") || candidate.has_attribute("module") { | ||
| EmbeddingStyleApplicability::Local | ||
| } else { | ||
| EmbeddingStyleApplicability::Global | ||
| }; | ||
| CssFileSource::new_css_modules().with_embedding_kind(CssEmbeddingKind::Html( | ||
| EmbeddingHtmlKind::Vue { applicability }, | ||
| )) | ||
| } else if ctx.host_file_source.is_astro() { | ||
| // Astro: <style is:global> is global; plain <style> is local | ||
| let applicability = if candidate.has_attribute("is:global") { | ||
| EmbeddingStyleApplicability::Global | ||
| } else { | ||
| EmbeddingStyleApplicability::Local | ||
| }; | ||
| CssFileSource::new_css_modules().with_embedding_kind(CssEmbeddingKind::Html( | ||
| EmbeddingHtmlKind::Vue { applicability }, | ||
| )) | ||
| } else if html_file_source.is_astro() { | ||
| // Astro: <style is:global> → Global; plain <style> → Local | ||
| let applicability = if element.is_style_scoped("is:global") { | ||
| EmbeddingStyleApplicability::Global | ||
| CssFileSource::new_css_modules().with_embedding_kind(CssEmbeddingKind::Html( | ||
| EmbeddingHtmlKind::Astro { applicability }, | ||
| )) | ||
| } else if ctx.host_file_source.is_svelte() { | ||
| // Svelte: plain <style> is local (global classes via :global() | ||
| // are detected at the selector level by the CSS semantic model) | ||
| CssFileSource::new_css_modules().with_embedding_kind(CssEmbeddingKind::Html( | ||
| EmbeddingHtmlKind::Svelte { | ||
| applicability: EmbeddingStyleApplicability::Local, | ||
| }, | ||
| )) | ||
| } else { | ||
| EmbeddingStyleApplicability::Local | ||
| CssFileSource::new_css_modules() | ||
| }; | ||
| CssFileSource::new_css_modules().with_embedding_kind(CssEmbeddingKind::Html( | ||
| EmbeddingHtmlKind::Astro { applicability }, | ||
| )) | ||
| } else if html_file_source.is_svelte() { | ||
| // Svelte: plain <style> → Local (global classes via :global() are | ||
| // detected at the class-selector level by the CSS semantic model) | ||
| CssFileSource::new_css_modules().with_embedding_kind(CssEmbeddingKind::Html( | ||
| EmbeddingHtmlKind::Svelte { | ||
| applicability: EmbeddingStyleApplicability::Local, | ||
| }, | ||
| )) | ||
| } else { | ||
| CssFileSource::new_css_modules() | ||
| }; | ||
|
|
||
| let file_source = DocumentFileSource::Css(file_source); | ||
| let (snippet, services) = element.children().iter().next().and_then(|child| { | ||
| let child = child.as_any_html_content()?; | ||
| let child = child.as_html_embedded_content()?; | ||
| let mut options = settings.parse_options::<CssLanguage>(biome_path, &file_source); | ||
| if html_file_source.is_vue() { | ||
| options.css_modules = CssModulesKind::Vue | ||
| } else if !html_file_source.is_html() { | ||
| options.css_modules = CssModulesKind::Classic | ||
| let doc_source = DocumentFileSource::Css(css_source); | ||
| let mut options = ctx | ||
| .settings | ||
| .parse_options::<CssLanguage>(ctx.biome_path, &doc_source); | ||
| if ctx.host_file_source.is_vue() { | ||
| options.css_modules = CssModulesKind::Vue; | ||
| } else if !ctx.host_file_source.is_html() { | ||
| options.css_modules = CssModulesKind::Classic; | ||
| } | ||
| let content = child.value_token().ok()?; | ||
| let parse = parse_css_with_offset_and_cache( | ||
| content.text(), | ||
| file_source.to_css_file_source().unwrap_or_default(), | ||
| content.text_range().start(), | ||
| cache, | ||
| content.text.text(), | ||
| css_source, | ||
| content.content_offset, | ||
| ctx.cache, | ||
| options, | ||
| ); |
There was a problem hiding this comment.
Embedded styles still ignore lang="scss".
You already carry tag attributes on EmbedCandidate, but this branch always materialises a CSS / CSS-modules file source and never switches the language from lang. So SCSS at-rules inside HTML, Vue, or Svelte <style> blocks will still be parsed as vanilla CSS.
| fn visit_jsx_reference_identifier(&mut self, reference: JsxReferenceIdentifier) -> Option<()> { | ||
| let name_token = reference.value_token().ok()?; | ||
| self.references.insert( | ||
| name_token.text_trimmed_range(), | ||
| name_token.token_text_trimmed(), | ||
| ); | ||
| Some(()) | ||
| } |
There was a problem hiding this comment.
Please pin this JSX branch with tests.
The tests in this module still only exercise plain JS references and HTML component names, so visit_jsx_reference_identifier can drift quietly. A tiny <Foo /> and <Foo.Bar /> case would do the job. Based on learnings, all code changes MUST include tests.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@crates/biome_service/src/workspace/document/services/embedded_value_references.rs`
around lines 148 - 155, Add unit tests that exercise the JSX branch by invoking
visit_jsx_reference_identifier via parsing snippets containing <Foo /> and
<Foo.Bar /> so the references set is populated for both simple and member JSX
names; update the test module that currently covers plain JS and HTML names to
include two new cases (one for "<Foo />" and one for "<Foo.Bar />") asserting
that the collected reference tokens include "Foo" and "Foo.Bar" (or the expected
token/Text ranges) so visit_jsx_reference_identifier in the
embedded_value_references service is pinned and will fail if regressed.
| ScssIncludeAtRule = | ||
| 'include' | ||
| name: AnyScssIncludeTarget | ||
| arguments: ScssIncludeArgumentList? | ||
| block: CssDeclarationOrRuleBlock? | ||
| ';'? |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
According to the official Sass documentation, does the @includeat-rule support an optionalusing (...) clause when passing a content block?
💡 Result:
Yes. The Sass @mixin/@include documentation states that when a mixin passes arguments to its content block via @content(...), the caller’s @include can (and in that case must) add a using (<arguments...>) clause to declare the content block parameters; otherwise, you omit using. [1]
Add using (...) clause support to ScssIncludeAtRule.
The Sass specification allows @include to accept an optional using (...) clause when the mixin's @content block expects arguments. The grammar currently omits this, so valid code like @include theme using ($arg) { ... } won't parse.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@xtask/codegen/css.ungram` around lines 2609 - 2614, The ScssIncludeAtRule
production is missing the optional "using (...)" clause; update
ScssIncludeAtRule to accept an optional using clause (e.g., add a
ScssIncludeUsingClause or ScssUsingClause nonterminal and include it as using:
ScssIncludeUsingClause? in ScssIncludeAtRule) placed after the include target
(name) and before the arguments/block, and implement the clause grammar to match
'using' '(' <argument list> ')' so the parser accepts constructs like "@include
theme using ($arg) { ... }".
| use xtask_codegen::update; | ||
| use xtask_glue::{Mode, Result, project_root}; | ||
|
|
||
| const WEB_FEATURES_DATA_URL: &str = "https://unpkg.com/web-features/data.json"; |
There was a problem hiding this comment.
Pin the web-features snapshot.
Fetching the unversioned WEB_FEATURES_DATA_URL makes this generator non-reproducible: rerunning the same commit later can emit different Rust, and Mode::Verify becomes time-dependent. Please pin a package version or commit and update it deliberately.
Also applies to: 532-563
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@xtask/codegen/src/generate_css_baseline.rs` at line 10, The constant
WEB_FEATURES_DATA_URL currently points to an unversioned URL which makes
generation non-reproducible; update the const WEB_FEATURES_DATA_URL to reference
a pinned version or specific commit (e.g., by changing the URL to include an
explicit package version or commit hash) so the generator emits stable Rust and
Mode::Verify is deterministic; ensure any other uses in this file (references
near lines 532-563) are left unchanged other than using the new pinned URL
constant.
Summary
Test Plan
Docs